﻿using Helpers;
using System.Collections.Generic;
using TaleWorlds.CampaignSystem.CharacterDevelopment;
using TaleWorlds.CampaignSystem.ComponentInterfaces;
using TaleWorlds.CampaignSystem.Encounters;
using TaleWorlds.CampaignSystem.Party;
using TaleWorlds.CampaignSystem.Roster;
using TaleWorlds.Core;
using TaleWorlds.Library;
using TaleWorlds.SaveSystem;

namespace TaleWorlds.CampaignSystem.MapEvents
{
  // 表示地图事件中的一个队伍
  public class MapEventParty
  {
    // 保存的字段，表示队伍的扁平化部队名册
    [SaveableField(2)]
    private FlattenedTroopRoster _roster;

    // 保存的字段，表示队伍对战斗的贡献值
    [SaveableField(3)]
    private int _contributionToBattle = 1;

    // 保存的字段，表示战斗开始时队伍的健康成员数量
    [SaveableField(9)]
    private int _healthyManCountAtStart = 1;

    // 保存的字段，表示在战斗中受伤的部队名册
    [SaveableField(7)]
    private TroopRoster _woundedInBattle = TroopRoster.CreateDummyTroopRoster();

    // 保存的字段，表示在战斗中死亡的部队名册
    [SaveableField(8)]
    private TroopRoster _diedInBattle = TroopRoster.CreateDummyTroopRoster();

    // 静态方法，用于收集对象，供保存系统使用
    internal static void AutoGeneratedStaticCollectObjectsMapEventParty(
      object o,
      List<object> collectedObjects)
    {
      ((MapEventParty)o).AutoGeneratedInstanceCollectObjects(collectedObjects);
    }

    // 实例方法，用于收集对象，供保存系统使用
    protected virtual void AutoGeneratedInstanceCollectObjects(List<object> collectedObjects)
    {
      collectedObjects.Add((object)this._roster);
      collectedObjects.Add((object)this._woundedInBattle);
      collectedObjects.Add((object)this._diedInBattle);
      collectedObjects.Add((object)this.Party);
    }

    // 静态方法，用于获取成员变量 Party 的值
    internal static object AutoGeneratedGetMemberValueParty(object o)
    {
      return (object)((MapEventParty)o).Party;
    }

    // 静态方法，用于获取成员变量 GainedRenown 的值
    internal static object AutoGeneratedGetMemberValueGainedRenown(object o)
    {
      return (object)((MapEventParty)o).GainedRenown;
    }

    // 静态方法，用于获取成员变量 GainedInfluence 的值
    internal static object AutoGeneratedGetMemberValueGainedInfluence(object o)
    {
      return (object)((MapEventParty)o).GainedInfluence;
    }

    // 静态方法，用于获取成员变量 MoraleChange 的值
    internal static object AutoGeneratedGetMemberValueMoraleChange(object o)
    {
      return (object)((MapEventParty)o).MoraleChange;
    }

    // 静态方法，用于获取成员变量 PlunderedGold 的值
    internal static object AutoGeneratedGetMemberValuePlunderedGold(object o)
    {
      return (object)((MapEventParty)o).PlunderedGold;
    }

    // 静态方法，用于获取成员变量 GoldLost 的值
    internal static object AutoGeneratedGetMemberValueGoldLost(object o)
    {
      return (object)((MapEventParty)o).GoldLost;
    }

    // 静态方法，用于获取成员变量 _roster 的值
    internal static object AutoGeneratedGetMemberValue_roster(object o)
    {
      return (object)((MapEventParty)o)._roster;
    }

    // 静态方法，用于获取成员变量 _contributionToBattle 的值
    internal static object AutoGeneratedGetMemberValue_contributionToBattle(object o)
    {
      return (object)((MapEventParty)o)._contributionToBattle;
    }

    // 静态方法，用于获取成员变量 _healthyManCountAtStart 的值
    internal static object AutoGeneratedGetMemberValue_healthyManCountAtStart(object o)
    {
      return (object)((MapEventParty)o)._healthyManCountAtStart;
    }

    // 静态方法，用于获取成员变量 _woundedInBattle 的值
    internal static object AutoGeneratedGetMemberValue_woundedInBattle(object o)
    {
      return (object)((MapEventParty)o)._woundedInBattle;
    }

    // 静态方法，用于获取成员变量 _diedInBattle 的值
    internal static object AutoGeneratedGetMemberValue_diedInBattle(object o)
    {
      return (object)((MapEventParty)o)._diedInBattle;
    }

    // 保存的属性，表示队伍的基础信息
    [SaveableProperty(1)]
    public PartyBase Party { get; private set; }

    // 返回战斗开始时队伍的健康成员数量
    public int HealthyManCountAtStart => this._healthyManCountAtStart;

    // 返回战斗中死亡的部队名册
    internal TroopRoster DiedInBattle => this._diedInBattle;

    // 返回战斗中受伤的部队名册
    internal TroopRoster WoundedInBattle => this._woundedInBattle;

    // 返回队伍对战斗的贡献值
    public int ContributionToBattle => this._contributionToBattle;

    // 重置队伍的战斗贡献值为队伍实力的平方根
    internal void ResetContributionToBattleToStrength()
    {
      this._contributionToBattle = (int)MathF.Sqrt(this.Party.TotalStrength);
    }

    // 返回队伍的扁平化部队名册
    public FlattenedTroopRoster Troops => this._roster;

    // 构造函数，初始化 MapEventParty 对象
    internal MapEventParty(PartyBase party)
    {
      this.Party = party;
      this.Update();
      this._healthyManCountAtStart = party.NumberOfHealthyMembers;
    }

    // 更新部队名册
    public void Update()
    {
      if (this._roster == null)
        this._roster = new FlattenedTroopRoster(this.Party.MemberRoster.TotalManCount);
      this._roster.Clear();
      foreach (TroopRosterElement troopRosterElement in (List<TroopRosterElement>)this.Party.MemberRoster.GetTroopRoster())
      {
        if (troopRosterElement.Character.IsHero)
        {
          if (!this._woundedInBattle.Contains(troopRosterElement.Character) && !this._diedInBattle.Contains(troopRosterElement.Character))
            this._roster.Add(troopRosterElement.Character, troopRosterElement.Character.HeroObject.IsWounded, troopRosterElement.Xp);
        }
        else
          this._roster.Add(troopRosterElement.Character, troopRosterElement.Number, troopRosterElement.WoundedNumber);
      }
    }

    // 判断是否为 NPC 队伍
    public bool IsNpcParty => this.Party != PartyBase.MainParty;

    // 获取可接收战利品的部队名册
    public TroopRoster RosterToReceiveLootMembers
    {
      get
      {
        return !this.IsNpcParty ? PlayerEncounter.Current.RosterToReceiveLootMembers : this.Party.MemberRoster;
      }
    }

    // 获取可接收战利品的囚犯名册
    public TroopRoster RosterToReceiveLootPrisoners
    {
      get
      {
        return !this.IsNpcParty ? PlayerEncounter.Current.RosterToReceiveLootPrisoners : this.Party.PrisonRoster;
      }
    }

    // 获取可接收战利品的物品名册
    public ItemRoster RosterToReceiveLootItems
    {
      get
      {
        return !this.IsNpcParty ? PlayerEncounter.Current.RosterToReceiveLootItems : this.Party.ItemRoster;
      }
    }

    // 保存的属性，表示获得的声望
    [SaveableProperty(7)]
    public float GainedRenown { get; set; }

    // 保存的属性，表示获得的影响力
    [SaveableProperty(8)]
    public float GainedInfluence { get; set; }

    // 保存的属性，表示士气的变化
    [SaveableProperty(9)]
    public float MoraleChange { get; set; }

    // 保存的属性，表示掠夺的金币数量
    [SaveableProperty(10)]
    public int PlunderedGold { get; set; }

    // 保存的属性，表示失去的金币数量
    [SaveableProperty(11)]
    public int GoldLost { get; set; }

    // 当部队成员被杀时调用
    public void OnTroopKilled(UniqueTroopDescriptor troopSeed)
    {
      FlattenedTroopRosterElement troopRosterElement = this._roster[troopSeed];
      CharacterObject troop = troopRosterElement.Troop;
      this.Party.MemberRoster.AddTroopTempXp(troop, -troopRosterElement.XpGained);
      if (!troop.IsHero && this.Party.IsActive)
        this.Party.MemberRoster.RemoveTroop(troop, troopSeed: troopSeed);
      this._roster.OnTroopKilled(troopSeed);
      this.DiedInBattle.AddToCounts(this._roster[troopSeed].Troop, 1);
      ++this._contributionToBattle;
    }

    // 当部队成员受伤时调用
    public void OnTroopWounded(UniqueTroopDescriptor troopSeed)
    {
      this.Party.MemberRoster.WoundTroop(this._roster[troopSeed].Troop, troopSeed: troopSeed);
      this._roster.OnTroopWounded(troopSeed);
      this.WoundedInBattle.AddToCounts(this._roster[troopSeed].Troop, 1, woundedCount: 1);
    }

    // 当部队成员逃跑时调用
    public void OnTroopRouted(UniqueTroopDescriptor troopSeed)
    {
    }

    // 获取指定的部队成员
    public CharacterObject GetTroop(UniqueTroopDescriptor troopSeed)
    {
      return this._roster[troopSeed].Troop;
    }

    public void OnTroopScoreHit(
    UniqueTroopDescriptor attackerTroopDesc, // 攻击者部队的唯一标识符
    CharacterObject attackedTroop,           // 被攻击的部队对象
    int damage,                              // 攻击造成的伤害值
    bool isFatal,                            // 攻击是否致命
    bool isTeamKill,                         // 是否为队友误杀
    WeaponComponentData attackerWeapon,      // 攻击者使用的武器数据
    bool isSimulatedHit)                     // 是否为模拟命中
{
    // 从扁平化的部队名册中获取攻击者的部队对象
    CharacterObject troop = this._roster[attackerTroopDesc].Troop;

    // 如果是队友误杀，则直接返回，不处理经验和战斗贡献
    if (isTeamKill)
        return;

    // 经验值变量
    int xpAmount;

    // 调用战斗经验模型，根据攻击者和被攻击者的属性计算经验值
    Campaign.Current.Models.CombatXpModel.GetXpFromHit(
        troop, 
        (CharacterObject)null, 
        attackedTroop, 
        this.Party, 
        damage, 
        isFatal, 
        isSimulatedHit ? CombatXpModel.MissionTypeEnum.SimulationBattle : CombatXpModel.MissionTypeEnum.Battle, 
        out xpAmount);

    // 通过随机数生成器调整经验值，使其更接近整数
    int num = xpAmount + MBRandom.RoundRandomized((float)xpAmount);

    // 如果攻击者不是英雄
    if (!troop.IsHero)
    {
        // 如果经验值大于0
        if (num > 0)
        {
            // 通过扁平化部队名册增加经验值
            int gainedXp = this._roster.OnTroopGainXp(attackerTroopDesc, num);

            // 在部队名册中为部队增加临时经验值
            this.Party.MemberRoster.AddTroopTempXp(troop, gainedXp);
        }
    }
    else
    {
        // 如果攻击者是英雄，分发战斗命中事件，更新英雄的战斗状态
        CampaignEventDispatcher.Instance.OnHeroCombatHit(
            troop, 
            attackedTroop, 
            this.Party, 
            attackerWeapon, 
            isFatal, 
            num);
    }

    // 增加队伍对战斗的贡献值
    this._contributionToBattle += num;
}


    // 提交经验值获取
    public void CommitXpGain()
    {
      if (this.Party.MobileParty == null)
        return;
      int xpToDistribute = 0;
      foreach (FlattenedTroopRosterElement troopRosterElement in this._roster)
      {
        CharacterObject troop = troopRosterElement.Troop;
        if (!troopRosterElement.IsKilled && troopRosterElement.XpGained > 0 && MobilePartyHelper.CanTroopGainXp(this.Party, troop, out int _))
        {
          int xpGainFromBattles = Campaign.Current.Models.PartyTrainingModel.CalculateXpGainFromBattles(troopRosterElement, this.Party);
          int sharedXp = Campaign.Current.Models.PartyTrainingModel.GenerateSharedXp(troop, xpGainFromBattles, this.Party.MobileParty);
          if (sharedXp > 0)
          {
            xpToDistribute += sharedXp;
            xpGainFromBattles -= sharedXp;
          }
          if (!troop.IsHero)
            this.Party.MemberRoster.AddXpToTroop(xpGainFromBattles, troop);
        }
      }
      MobilePartyHelper.PartyAddSharedXp(this.Party.MobileParty, (float)xpToDistribute);
      SkillLevelingManager.OnBattleEnd(this.Party, this._roster);
    }
  }
}
